#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
三班制排班接口修复方案
"""

import sys
import os
import logging
import json
from datetime import datetime, timedelta, date
import uuid
import random
from collections import Counter

# 设置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from app import create_app, db
from app.three_shift import ThreeShiftScheduler
from app.models import ShiftAssignment, ScheduleResult, TimeSlot
from app.new_models import CareElderDemand, DigitalEmployeeSkills, CareGbNursingAction
from app.care_models import AppUser, AppUserDetail
from app.model_adapters import ElderdemandAdapter, AttendantskillsAdapter

def apply_fixes():
    """应用修复方案"""
    logger.info("=" * 80)
    logger.info("应用三班制排班接口修复方案")
    logger.info("=" * 80)

    with create_app().app_context():
        # 创建三班制排班调度器
        scheduler = ThreeShiftScheduler()

        # 修改generate_daily_schedule方法
        original_generate_daily_schedule = scheduler.generate_daily_schedule

        def improved_generate_daily_schedule(self, target_date, caregivers, elders, shift_start_time=None):
            """改进的generate_daily_schedule方法"""
            # 调用原方法获取班次分配
            result = original_generate_daily_schedule(target_date, caregivers, elders, shift_start_time)

            # 获取班次分配
            shift_assignments = result.get("shift_assignments", [])

            # 创建老人排班结果字典
            elder_schedules = {}

            # 为每个老人生成照护时间线
            for elder in elders:
                elder_id = elder.elder
                self.logger.info(f"为老人 {elder_id} 生成照护时间线")

                # 获取老人的护理需求
                elder_demands = ElderdemandAdapter.query_filter_by(elder=elder_id, arrange="1").all()
                self.logger.info(f"获取到 {len(elder_demands)} 个护理需求记录")

                # 解析老人的护理动作需求
                action_ids = []
                for demand in elder_demands:
                    if demand.actions:
                        action_ids.extend(
                            [
                                int(action_id.strip())
                                for action_id in demand.actions.split(",")
                                if action_id.strip().isdigit()
                            ]
                        )

                self.logger.info(f"护理动作ID: {action_ids}")

                # 获取护理动作详情
                actions = []
                if action_ids:
                    actions = CareGbNursingAction.query.filter(CareGbNursingAction.id.in_(action_ids)).all()

                # 创建时间段列表
                time_slots = self.time_slots_per_day  # 一天分为72个时间段
                time_interval_minutes = self.time_interval_minutes  # 每个时间段为20分钟

                time_slot_list = []
                for i in range(time_slots):
                    hours = (i * time_interval_minutes) // 60
                    minutes = (i * time_interval_minutes) % 60
                    next_hours = ((i + 1) * time_interval_minutes) // 60
                    next_minutes = ((i + 1) * time_interval_minutes) % 60

                    # 处理跨天的情况
                    if next_hours >= 24:
                        next_hours -= 24

                    time_slot_str = f"{hours:02d}:{minutes:02d}-{next_hours:02d}:{next_minutes:02d}"
                    time_slot_list.append(time_slot_str)

                # 创建照护时间线
                care_timeline = []

                # 跟踪护理员的工作负荷
                caregiver_workload = {caregiver.id: 0 for caregiver in caregivers}

                # 为每个时间段分配活动和护理员
                for i, time_slot_str in enumerate(time_slot_list):
                    # 解析时间段
                    start_time = time_slot_str.split("-")[0]

                    # 检查是否是睡眠时间
                    is_sleep_time = False
                    hour = int(start_time.split(":")[0])
                    if 22 <= hour or hour < 6:
                        is_sleep_time = True

                    if is_sleep_time:
                        # 睡眠时间段，使用特殊处理
                        care_timeline.append({
                            "Activity": "老年人睡眠状况观察记录",
                            "TimeSlot": time_slot_str,
                            "Caregiver": "lack",
                            "ActivityId": "10",
                            "CaregiverId": "-1"
                        })
                        continue

                    # 如果没有护理需求，使用None
                    if not action_ids:
                        care_timeline.append({
                            "Activity": "None",
                            "TimeSlot": time_slot_str,
                            "Caregiver": "None",
                            "ActivityId": "0",
                            "CaregiverId": "0"
                        })
                        continue

                    # 根据老人的需求数量分配活动
                    # 计算每个需求应该分配的时间段数量
                    non_sleep_slots = sum(1 for slot in time_slot_list if not (22 <= int(slot.split("-")[0].split(":")[0]) or int(slot.split("-")[0].split(":")[0]) < 6))
                    slots_per_action = max(1, non_sleep_slots // len(action_ids))

                    # 确定当前时间段应该分配的活动
                    action_index = (i % non_sleep_slots) // slots_per_action
                    if action_index >= len(action_ids):
                        action_index = len(action_ids) - 1

                    selected_action_id = action_ids[action_index]

                    # 获取活动名称
                    action = next((a for a in actions if a.id == selected_action_id), None)
                    if not action:
                        care_timeline.append({
                            "Activity": "未知活动",
                            "TimeSlot": time_slot_str,
                            "Caregiver": "None",
                            "ActivityId": str(selected_action_id),
                            "CaregiverId": "0"
                        })
                        continue

                    # 获取活动所需的护理技能
                    action_nursing_ids = []
                    if action.nursing_id:
                        action_nursing_ids = [
                            int(nursing_id.strip())
                            for nursing_id in action.nursing_id.split(",")
                            if nursing_id.strip().isdigit()
                        ]

                    # 匹配护理员
                    matched_caregivers = []
                    for caregiver in caregivers:
                        # 解析护理员技能
                        caregiver_skills = self.parse_skills(caregiver.skills)

                        # 检查护理员是否具备所需技能
                        if not action_nursing_ids or any(skill_id in caregiver_skills for skill_id in action_nursing_ids):
                            matched_caregivers.append(caregiver)

                    if matched_caregivers:
                        # 根据工作负荷选择护理员
                        matched_caregivers.sort(key=lambda c: caregiver_workload[c.id])
                        selected_caregiver = matched_caregivers[0]

                        # 更新护理员工作负荷
                        caregiver_workload[selected_caregiver.id] += 1

                        care_timeline.append({
                            "Activity": action.name,
                            "TimeSlot": time_slot_str,
                            "Caregiver": selected_caregiver.attendant_name,
                            "ActivityId": str(selected_action_id),
                            "CaregiverId": selected_caregiver.id
                        })
                    else:
                        # 没有匹配的护理员，使用lack
                        care_timeline.append({
                            "Activity": action.name,
                            "TimeSlot": time_slot_str,
                            "Caregiver": "lack",
                            "ActivityId": str(selected_action_id),
                            "CaregiverId": "-1"
                        })

                # 将照护时间线添加到老人排班结果字典
                elder_schedules[elder_id] = care_timeline

            # 更新结果字典
            result["elder_schedules"] = elder_schedules

            return result

        # 替换方法
        scheduler.generate_daily_schedule = improved_generate_daily_schedule.__get__(scheduler, ThreeShiftScheduler)

        # 修改save_schedule_results方法
        original_save_schedule_results = scheduler.save_schedule_results

        def improved_save_schedule_results(self, target_date, shift_assignments, elder_schedules, batch_number=None):
            """改进的save_schedule_results方法"""
            # 获取批次号
            if batch_number is None:
                batch_number = self.get_next_batch_number()

            # 保存班次分配
            for assignment in shift_assignments:
                db.session.add(assignment)

            # 检查是否需要隐藏未分配活动
            from config_params import three_shift_params
            hide_unassigned = three_shift_params.get("hide_unassigned_activities", False)

            # 保存照护时间线
            if elder_schedules:
                self.logger.info(f"保存照护时间线，共 {len(elder_schedules)} 个老人")

                # 获取当前时间
                current_datetime = datetime.now()

                # 确保target_date是日期对象
                if isinstance(target_date, str):
                    plan_date = datetime.strptime(target_date, "%Y-%m-%d").date()
                else:
                    plan_date = target_date

                # 为每个老人保存照护时间线
                for elder_id, care_timeline in elder_schedules.items():
                    self.logger.info(f"保存老人 {elder_id} 的照护时间线，共 {len(care_timeline)} 个时间段")

                    # 如果启用了隐藏未分配活动的功能，过滤掉未分配活动
                    filtered_timeline = []
                    if hide_unassigned:
                        # 先过滤掉未分配活动，再进行后续处理
                        for entry in care_timeline:
                            if entry["Caregiver"] != "None":
                                filtered_timeline.append(entry)
                            else:
                                self.logger.info(f"预过滤未分配活动: {entry['TimeSlot']} - {entry['Activity']}")

                        # 如果过滤后没有任何条目，使用原始条目
                        if not filtered_timeline:
                            self.logger.warning("过滤后没有任何条目，使用原始条目")
                            filtered_timeline = care_timeline
                        else:
                            self.logger.info(f"预过滤后的照护时间线包含 {len(filtered_timeline)} 个时间段（原 {len(care_timeline)} 个）")
                            # 更新原始时间线，确保后续处理使用过滤后的时间线
                            care_timeline = filtered_timeline.copy()
                    else:
                        filtered_timeline = care_timeline

                    # 创建排班结果记录
                    schedule_result = ScheduleResult(
                        id=str(uuid.uuid4()),
                        elder=elder_id,
                        schedule_date=current_datetime,
                        schedule_data=json.dumps(filtered_timeline, ensure_ascii=False),
                        plan_date=plan_date,
                        batch_number=batch_number,
                        create_time=current_datetime,
                        update_time=current_datetime,
                        status="active"
                    )

                    # 保存排班结果记录
                    db.session.add(schedule_result)
                    db.session.flush()

                    # 保存时间段记录
                    time_slots_to_add = []
                    for i, entry in enumerate(filtered_timeline):  # 使用过滤后的时间线
                        time_slot = TimeSlot(
                            id=str(uuid.uuid4()),
                            schedule_result_id=schedule_result.id,
                            elder=elder_id,
                            time_slot=entry["TimeSlot"],
                            activity=entry["Activity"],
                            activity_id=entry["ActivityId"],
                            caregiver=entry["Caregiver"],
                            caregiver_id=entry["CaregiverId"],
                            time_order=i,
                            schedule_date=current_datetime,
                            plan_date=plan_date,
                            batch_number=batch_number,
                            create_time=current_datetime,
                            update_time=current_datetime,
                            status="active"
                        )
                        time_slots_to_add.append(time_slot)

                    # 批量保存时间段记录
                    db.session.bulk_save_objects(time_slots_to_add)

                    self.logger.info(f"保存了 {len(time_slots_to_add)} 个时间段记录")

                # 提交事务
                db.session.commit()

            return {
                "success": True,
                "message": "排班计划保存成功",
                "batch_number": batch_number
            }

        # 替换方法
        scheduler.save_schedule_results = improved_save_schedule_results.__get__(scheduler, ThreeShiftScheduler)

        # 测试修复后的方法
        logger.info("测试修复后的方法")

        # 获取所有护理员
        caregivers = scheduler.get_caregivers()
        logger.info(f"获取到 {len(caregivers)} 个护理员")

        # 获取所有老人
        elders = scheduler.get_elders()
        logger.info(f"获取到 {len(elders)} 个老人")

        # 限制老人和护理员数量，加快测试速度
        max_elders = 1
        max_caregivers = len(caregivers)  # 使用所有可用的护理员

        elders = elders[:max_elders]
        caregivers = caregivers[:max_caregivers]

        logger.info(f"使用 {len(elders)} 个老人和 {len(caregivers)} 个护理员")

        # 生成排班计划
        result = scheduler.generate_and_save_schedule(
            schedule_type='daily',
            num_days=1,
            start_date=date.today().strftime("%Y-%m-%d"),
            generate_care_timeline=True,
            shift_mode=3,  # 三班制
            time_slots_per_day=72,  # 一天分为72个时间段
            time_interval_minutes=20  # 每个时间段为20分钟
        )

        logger.info(f"排班计划生成结果: {result}")

        # 查询最新的照护计划总表记录
        latest_results = ScheduleResult.query.filter(
            ScheduleResult.schedule_date >= datetime.now() - timedelta(minutes=5)
        ).order_by(ScheduleResult.schedule_date.desc()).all()

        if not latest_results:
            logger.info("没有找到最近生成的照护计划总表记录")
            return

        logger.info(f"找到 {len(latest_results)} 条最近生成的照护计划总表记录")

        # 查询照护计划分表记录
        for result in latest_results[:1]:  # 只检查第一条记录
            logger.info("\n照护计划总表记录:")
            logger.info(f"  ID: {result.id}")
            logger.info(f"  老人: {result.elder}")
            logger.info(f"  日期: {result.schedule_date}")

            # 查询照护计划分表
            time_slots = TimeSlot.query.filter_by(schedule_result_id=result.id).order_by(TimeSlot.time_order).all()
            logger.info(f"  照护计划分表记录数: {len(time_slots)}")

            # 统计活动类型和护理员分配情况
            activity_counts = Counter()
            caregiver_counts = Counter()

            for slot in time_slots:
                # 统计活动类型
                if slot.activity not in activity_counts:
                    activity_counts[slot.activity] = 0
                activity_counts[slot.activity] += 1

                # 统计护理员分配情况
                if slot.caregiver not in caregiver_counts:
                    caregiver_counts[slot.caregiver] = 0
                caregiver_counts[slot.caregiver] += 1

            # 显示活动类型统计
            logger.info("\n  活动类型统计:")
            for activity, count in activity_counts.most_common():
                logger.info(f"    {activity}: {count}次")

            # 显示护理员分配统计
            logger.info("\n  护理员分配统计:")
            for caregiver, count in caregiver_counts.most_common():
                logger.info(f"    {caregiver}: {count}次")

            # 显示前10个时间段的详细信息
            logger.info("\n  前10个时间段的详细信息:")
            for i, slot in enumerate(time_slots[:10]):
                logger.info(f"    {i+1}. 时间: {slot.time_slot}, 活动: {slot.activity}, 护理员: {slot.caregiver}")

if __name__ == "__main__":
    apply_fixes()
